<?php
/**
 * Created by PhpStorm.
 * User: Qch
 * Date: 2016/8/13
 * Time: 20:52
 */

namespace Aoe\Core;

use Aoe\Database\Database;
use Aoe\Emulator\Smart;
use Aoe\Intent\Render\Render;
use Aoe\Intent\Request\Channel;
use Aoe\Intent\Request\Http;
use Aoe\Intent\Response;
use Aoe\Intent\Router;
use Aoe\Util\Bus\Accessor;
use Aoe\Util\Bus\Config\Config;
use Aoe\Util\Bus\Config\Configurable;
use Aoe\Util\Bus\Store\Arr;
use Aoe\Util\Bus\Store\Obj;
use Aoe\Util\Exception;
use Aoe\Util\Language;
use Aoe\Util\Logger\Logger;
use Aoe\Util\Logger\NameRecorder;
use Aoe\Util\Manager\ClosureCollection;
use Aoe\Util\Template;
use Throwable;

/**
 * # 应用程序入口
 *
 *    * 包装了 Container 类
 *    * 和 Module 实现了级联配置
 *    * 通过 start 启动解析
 *
 *
 * @method Language Language()   本地化
 * @method Router   Router()     路由
 * @method Template Template()   视图模板解析
 * @method Database Database()   数据库
 * @method Smart    Smart()      模式集
 * @method Logger   Logger()     控制台
 *
 */
class Kernel
{
    /**
     * 实现配置功能
     */
    use Configurable;

    const string RECORD_KEY = '内核';
    
    /**
     * @var ?Container 对象生成器
     */
    private(set) ?Container $container = null {
        get {
            if (!$this->container) {
                $this->container = new Container($this->config->get(Container::KEY_SERVICE, []));
                // 添加本体引用
                $this->container->set(class_basename($this), $this);
            }
            return $this->container;
        }
    }

    /**
     * @var ?ClosureCollection<Module> 模块管理器
     */
    private ?ClosureCollection $modules = null {
        get {
            if (!$this->modules) {
                //初始化模块管理器
                $this->modules = new ClosureCollection(
                    function ($name) {
                        $name = ucfirst($name);
                        try {
                            $class = "\\Application\\$name\\$name";
                            return $this->container->createObject($class, [$name], false);
                        } catch (Throwable) {}
                        // 返回默认模块对象
                        return new Common($this, $name);
                    }
                );
            }
            return $this->modules;
        }
    }
    /**
     * @var NameRecorder|null 日志记录器
     */
    private(set) ?NameRecorder $recorder = null {
        get {
            if (!$this->recorder) $this->recorder = new NameRecorder(
                $this->Logger(),
                $this->Language()->translate(self::RECORD_KEY)
            );
            return $this->recorder;
        }
    }

    /**
     * ## 启动整个处理程序
     *
     */
    public function start(): void
    {
        /**
         * ## 1、加载内核配置
         */
        $this->config = new Config(new Accessor(Arr::getInstance(), Config::file(__DIR__)));
        
        /**
         * ## 2、基础控制台
         */
        $this->Logger()->setTranslator($this->Language()->translate(...));
        
        /**
         * ## 3、初始化加载器错误信息处理 *当前使用composer，该功能停用
         */
        // $loader->setErrorHandler(fn($error, $context) => $this->getRecorder()->Error($error, $context, 2));
        
        /**
         * ## 4、初始化异常处理
         */
        Exception::setTranslator($this->Language()->translate(...));
        
        /**
         * ## 5、加载扩展配置
         */
        $this->config = $this->config->branch(
            new Accessor(Obj::getInstance(), Config::file(__DATA_DIR__, '__core__', '.json'))
        );

        /**
         * ## 6、语言设置，位置待调整
         */
        $this->Language()->compile(__DATA_DIR__);

        /**
         * ## 7、执行请求并输出（这是整个框架的核心控制部分）
         */
        Render::print($this->_get_response());
        //Render::print($this->_get_response()->openTrace($this->recorder, Logger::ALL));
    }
    private function _get_response(): Response
    {
        if (!is_locked()) {
            $r = new Channel($this, INSTALL_CMD)->fire();
            if ($r->error || !is_locked()) return $r;
        }

        if (php_sapi_name() === 'cli') return new Channel($this, 'cli')->fire();
        return new Http($this)->fire();
    }
    
    /**
     * ## 获取服务
     *
     * @param string $name 服务名称
     * @param ?array $arguments
     *
     * @return object
     * @throws \Exception
     */
    public function __call(string $name, ?array $arguments = null): object
    {
        return $this->container->__call($name, $arguments);
    }

    /**
     * ## 获取模块对象
     *
     * @param string $name 模块名称
     *
     * @return Module
     * @throws \Exception
     */
    public function getModule(string $name): Module
    {
        return $this->modules->get($name);
    }
}